﻿// A flow executes a graph of tasks
define([
    'Wjs/Wjs'
],
function () {
    'use strict';

    var Flow = Wjs.defineOnce({

        type: 'Flow',

        internal: {

            construct: function (cfg) {

                this.tasks = {}; // The tasks that are going to be executed by this flow

                this.startTaskId = cfg.startTaskId; // The id of task that starts executing

                this.results = {}; // The results of executing task

                if (cfg.tasks) {
                    this.addTasks(cfg.tasks);
                }
            },

            onBeforeTypeDefined: function () {

                var FlowTask = Wjs.define({

                    type: 'FlowTask',

                    internal: {

                        //'abstract': [
                        //    'run',
                        //    'route'
                        //],

                        construct: function (cfg) {

                            this.id = ''; // The id of the task

                            this.async = false; // Whether the task is executed synchronously or asynchronously

                            this.isRunning = false;

                            // Set up the handlers
                            this.run = cfg.run;

                            this.successHandler = cfg.successHandler;

                            this.onError = cfg.onError;
                        }
                    }
                });
            }
        },

        defaultChildType: 'FlowTask',

        addTask: function (task) {

            this.tasks[task.id] = task;
            task.context = this;
        },

        addTasks: function (tasks) {
            var task;

            for (var id in tasks) {

                task = tasks[id];

                task.id = id;

                this.addTask(task);
            }
        },

        getTask: function (id) {

            return this.tasks[id];
        },

        start: function () {
            var task = this.getTask(this.startTaskId);

            this.executeTask(task);
        },

        executeTask: function (task) {
            var nextTask = null;

            if (this.stopped) {
                return;
            }

            try {

                task.isRunning = true;

                if (task.isBlocking) {

                    task.run(this);

                    Wjs.wait(
                        function () { // test
                            return !task.isRunning; // Wait until the task stops running
                        },
                        function () { // callback

                            if (task.successHandler) {
                                nextTask = task.successHandler(this);
                            }

                            if (nextTask) {
                                this.executeTask(nextTask);
                            }
                        },
                        200,
                        this);
                }
                else { // Non blocking

                    task.run(this);

                    if (task.successHandler) {
                        nextTask = task.successHandler(this);
                    }

                    task.isRunning = false;
                }

            }
            catch (error) {

                if (task.onError) {
                    nextTask = task.onError(this, error);
                }
                else {

                    Wjs.alert({
                        title: 'Error executing task',
                        text: error
                    });
                }
            }

            if (nextTask) {
                this.executeTask(nextTask);
            }
        },

        stop: function () {
            this.stopped = true;
        }

    });

    return Flow;

});